vlwkaos' digital garden

Rust - Traits, derive and Generic Types

Trait

  • 다른 언어 interface
trait Parsers {
    fn bark(&self) {

    }
    fn run(&self) {

    }
    // signature만 있는 경우, abstract역할
}

// 걍 앞에 쓰는거만 다르네
impl Parsers for TypeName {
    // override
    fn bark(&self) {
        
    }

}

use std::fmt;

#[derive(Debug)]
struct Cat {
    name: String,
    age: u8
}

impl fmt::Display for Cat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}, {}", self.name, self.age);
    }
}

fn main() {
    let ma = Cat {
        name: "aa".to_string(),
        age: 9,
    };
    println!("{ma}");
}

Trait as bounds

  • trait 내부에는 구현을 하지 않고 제너릭을 활용하여 unit type의 구분을 이용하여 입출력 타입을 제어 where T: FightFromDistance + Debug
  • abstract impl

from and into

  • trait = 초능력
  • this type implements (trait)
  • from은 다른 타입에서 내 타입으로 어떻게 변환할지 구현
    • 예를 들어 String::from(30) 일때 30을 "30"으로 한다던가 (실제 그런건 아니고 가정하는거임)
  • into는 From trait을 호출함. 타입 정의가 되어있어야함
fn main() {
    let a = String::from("Daa"); // make typedef String from xxx
    let b: String = "asdf".into(); // xxx -> into, typedef String

    let vv = Vec::from([1,2,3]); // [i32;3] from이 있는거임 From[T;N] trait
}

Implementing From


fn print_vec<T: Display>(input: &Vec<T>) {
    for item in input {
        print!("{item} ");
    }
    println!();

}

fn main() {
    let x = String::from("thth");
    print_vec(&array_vec);

    let str_vec = Vec::from("What kind of vec is this?");
    print_vec(&str_vec);

    let string_vec = Vec::from("What kind of Vec is a String vec?");
    print_vec(&string_vec);

}

// 제공할 Type -> Struct 변환
impl From<Type> for STRUCT {

}

From implement했으면 into() 는 자동으로 생김 ...iter().for_each().into()

Blanket trait Implementations

감싼다. implementing trait for every type that you want to have

trait Prints {
    fn print() {
        println!("asdf");
    }
}

struct Person;
struct Building;

// 아무 타입에 대해 부여하기(?)
impl<T> Prints for T {
    
}

fn main() {
    let p = Person;
    let b = Building;
    p.print();
}

// Debug에 대해서만 Prints trait을 적용 타이핑
// trait boundary
trait Prints: Debug {
    //...
    // 이런식으로 따로따로도 가능하다
    fn asdf($self) where Self: Display {

    }
}

impl<T: Debug> Prints for T {

}

AsRef trait

  • cheap version of refToRef
    • Borrow와 형태는 유사. Borrow는 T에 impl되어있음
    • 절대로 실패하면 안되므로 Monad 처리해야함
  • 비싼 conversion은 From trait
use std::fmt::Display;

// T로 convert될 수 있는 모든 타입에 대해 받을 수 있음
fn print_it<T: Display + AsRef<str>>(input: T) {
    println!("{input}");
}

fn main() {
    print_it("asdfasdf");
    print_it(String::from("asdfasdf"));
}

Debug

객체 속성을 출력하기 위해서 trait 설정을 해야한다.

#[derive(Debug)]
struct Object {
 //...
}

이런식으로 하고 나중에

// print debug
// {:?} primitive는 자동으로 해준다.
// pretty print
// {:#?}
println!("{:#?}", o);

Display

use std::fmt;

#[derive(Display)]
struct Object {
//...
}

impl fmt::Display for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {}) and Area: {}", self.width, self.height, self.area())
    }
}

//...

println!("{}", o);

기타

  • 비교용: Eq, PartialEq, Ord, PartialOrd
  • Clone, T에서 copy를 통해 &T를 생성하기 위함
  • Copy, type에 'move semantics'대신에 'copy semantics'를 부여함
  • Hash, &T에서 해쉬값을 뽑아냄
  • Default

&T는 인스턴스?


generic

fn give_thing<T>(input: T) -> T {
    input
}

// Display trait이 있는 애들만
fn give_th<T: Display>(input: T) -> T {
    println!("{}", input); // Display
    input
}

// PartialOrd; Ordinal 순서용 compare용
// <... > generic을 where 절을 이용해도됨
fn aaaa<T: Display, U: Display + PartialOrd>(statement: T, num1: U, num2: U) {
    println!("{} is {} greater than {}? {}", statement, num1, num2, num1 > num2);
}

fn aaaa<T, U>(statement: T, num1: U, num2: U) 
where T: Display
{
    println!("{} is {} greater than {}? {}", statement, num1, num2, num1 > num2);
}


Referred in

Rust - Traits, derive and Generic Types